﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
using Microsoft.WindowsAzure.ServiceRuntime;
using System.Data.Services.Client;
using System.Data.Services.Common;

namespace webjies.DataLayer
{
    public class TableStorage : IDisposable
    {
        static string _connectionString;
        static CloudStorageAccount _storageAccount;
        static CloudTableClient _tableClient;

        static TableStorage()
        {
            // Get connection string from settings.
            _connectionString = RoleEnvironment.GetConfigurationSettingValue("StorageConnectionString");

            // Reference storage account from connection string. 
            _storageAccount = CloudStorageAccount.Parse(_connectionString);

            // Create Table service client.
            _tableClient = _storageAccount.CreateCloudTableClient();
        }

        public static void InitStorage()
        {
            //Create all the tables
            var entitiesTypes = from t in System.Reflection.Assembly.GetExecutingAssembly().GetTypes()
                                where typeof(TableStorageEntity).IsAssignableFrom(t)
                                        && t.IsClass && !t.IsAbstract
                                select t;
            foreach (var t in entitiesTypes)
            {
                _tableClient.DeleteTableIfExist(GetTableName(t));

                _tableClient.CreateTableIfNotExist(GetTableName(t));
            }
        }

        [ThreadStatic]
        TableServiceContext _context;

        public TableStorage()
        {
            if (_context != null)
                throw new ApplicationException("There is already an open context");

            _context = _tableClient.GetDataServiceContext();
        }

        public static string GetTableName<T>()
                where T : TableStorageEntity
        {
            return GetTableName(typeof(T));
        }
        public static string GetTableName(Type entityType)
        {
            return string.Format("{0}Table", entityType.Name);
        }

        public DataServiceQuery<T> Query<T>()
                where T : TableStorageEntity
        {
            return _context.CreateQuery<T>(GetTableName<T>());
        }

        public void Delete<T>(T entity)
                where T : TableStorageEntity
        {
            _context.DeleteObject(entity);
        }

        public void Add<T>(T entity)
                where T : TableStorageEntity
        {
            _context.AddObject(GetTableName<T>(), entity);
        }

        public void Update<T>(T entity)
                where T : TableStorageEntity
        {
            _context.UpdateObject(entity);
        }

        public void SaveChanges()
        {
            _context.SaveChanges();
        }
        public void SaveChangesBatch()
        {
            _context.SaveChanges(SaveChangesOptions.Batch);
        }

        public void Dispose()
        {
            _context = null;
        }
    }

    [DataServiceKey("PartitionKey", "RowKey")]
    public abstract class TableStorageEntity
    {
        #region Required table service properties
        public string PartitionKey { get; set; }

        public string RowKey { get; set; }

        public DateTime Timestamp { get; set; }
        #endregion
    }
}